/*
    Quaxx - Just another ataxx clone
    Copyright (C) 2010  Manuel Córdoba Ruiz

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "tablero.h"
#include <iostream>




Tablero::Tablero(){
	fondo.load("images/tablero.png");
	ficha1=0;
	imagenficha1.load("images/rojo.png");
	ficha2=2;
	tipo_oponente=0;  // Tipo de oponente: 0 Humano, 1 Ordenador
	imagenficha2.load("images/azul.png");
	setMinimumSize(560,560);
	coloresfichas[0]="rojo";
	coloresfichas[1]="verde";
	coloresfichas[2]="azul";
	coloresfichas[3]="amarillo";
	coloresfichas[4]="negro";
	coloresfichas[5]="blanco";
}

Tablero::~Tablero(){

}

void Tablero::mousePressEvent(QMouseEvent *event){
	if (event->button() == Qt::LeftButton) {
		casilla origen;
		origen=getCasilla(event->pos().x(),event->pos().y());
		col_origen  = origen.columna;
		fila_origen = origen.fila;
		if(tab[fila_origen][col_origen]==turno){
			casilla_sel=true;
			this->repaint();
		}
	}
}

void Tablero::mouseMoveEvent(QMouseEvent *event){
	pos_x = event->pos().x();
	pos_y = event->pos().y();
	this->repaint();
}

void Tablero::mouseReleaseEvent(QMouseEvent *event){
	if(turno==1 or (turno==2 && tipo_oponente==0)){ // Compruebo que el jugador sea el 1 o que sea el 2 siendo tambien humano.
		if(event->button() == Qt::LeftButton){
			casilla aux = getCasilla(event->pos().x(),event->pos().y());
			int col_destino = aux.columna;
			int fila_destino = aux.fila;
			int incx[] = { -1, -1, -1, 0, 0, 1, 1, 1};
			int incy[] = { -1, 0, 1, -1, 1, -1, 0, 1};
			int incx2[] = { -2, -2, -2, -2, -2, -1, -1, 0, 0, 1, 1, 2, 2, 2, 2, 2};
			int incy2[] = { -2, -1, 0, 1, 2, -2, 2, -2, 2, -2, 2, -2, -1, 0, 1, 2};
			if(tab[fila_origen][col_origen]==turno && tab[fila_destino][col_destino]==0){
				if(fila_destino!=fila_origen || col_destino!=col_origen){  // Evito coger y soltar en la misma casilla
					for(int i=0;i<8;i++){  // Compruebo si hemos soltado el ratón a distancia 1
						if(col_origen+incx[i]==col_destino && fila_origen+incy[i]==fila_destino){
							tab[fila_destino][col_destino]=turno;  // Pongo una nueva ficha
							fichas[turno-1]++;
							compruebaMovimiento(fila_destino,col_destino);  // Compruebo si me como alguna ficha del contrincante
							this->cambiaturno();  // Cambio el turno del jugador
							guardaMovimiento();
						}
					}
	
	
					for(int i=0;i<16;i++){// Compruebo si se ha soltado el ratón a distancia 2
						if(col_origen+incx2[i]==col_destino && fila_origen+incy2[i]==fila_destino){
							tab[fila_origen][col_origen]=0;  // Elimino la ficha de la casilla origen
							tab[fila_destino][col_destino]=turno;  // La pongo en la casilla destino
							compruebaMovimiento(fila_destino,col_destino);  // Compruebo si me como alguna ficha del contrincante;
							this->cambiaturno();  // Cambio el turno del jugador
							guardaMovimiento();
						}
					}
				}
			}
			casilla_sel=0;
			repaint();
			compruebaGanar();
		}
	}
}

int Tablero::getTurno(){
	return turno;
}

void Tablero::setColorFicha(int jugador, int color){
	QString ficha;
	ficha="images/";
	if(jugador==1){
		ficha1=color;
		ficha.append(coloresfichas[color]);	
		ficha.append(".png");
		imagenficha1.load(ficha);
	}else if(jugador==2){
		ficha2=color;
		ficha.append(coloresfichas[color]);	
		ficha.append(".png");
		imagenficha2.load(ficha);
	}
	repaint();
}

int Tablero::getColorFicha(int jugador){
	if(jugador==1){
		return ficha1;
	}else if(jugador==2){
		return ficha2;
	}else{  // Esta situacion nunca se debe dar, pero evita el aviso que da el compilador de que una funcion int no devuelve nada.
		return 0;
	}
}

int Tablero::getTipoOponente(){
	return tipo_oponente;
}

void Tablero::setTipoOponente(int tipo){
	tipo_oponente=tipo;
}

bool Tablero::puedeMover(int jugador){
	int incx[] = { -1, -1, -1, 0, 0, 1, 1, 1};
	int incy[] = { -1, 0, 1, -1, 1, -1, 0, 1};
	int incx2[] = { -2, -2, -2, -2, -2, -1, -1, 0, 0, 1, 1, 2, 2, 2, 2, 2};
	int incy2[] = { -2, -1, 0, 1, 2, -2, 2, -2, 2, -2, 2, -2, -1, 0, 1, 2};
	int auxi, auxj;
	bool movimiento=false;
	int i=0,j=0;
	while(i<7 && !movimiento){
		j=0;
		while(j<7 && !movimiento){
			if(tab[i][j]==jugador){
					for(int k=0;k<8;k++){
						auxi=i+incy[k];
						auxj=j+incx[k];
						if(auxi>0 && auxj>0 && auxi<7 && auxj<7 && tab[auxi][auxj]==0) movimiento=true;
					}

					for(int k=0;k<16;k++){
						auxi=i+incy2[k];
						auxj=j+incx2[k];
						if(auxi>0 && auxj>0 && auxi<7 && auxj<7 && tab[auxi][auxj]==0) movimiento=true;
					}
			}
			j++;
		}
		i++;
	}
	return movimiento;
}

void Tablero::compruebaMovimiento(int fila, int columna){
	int i,j;

	// Vectores auxiliares que emparejados identifican las casillas que rodean a una casilla dada
	int auxy[8]={fila-1,   fila-1, fila-1,   fila,     fila,     fila+1,   fila+1, fila+1};	
	int auxx[8]={columna-1,columna,columna+1,columna-1,columna+1,columna-1,columna,columna+1};
	// Recorro los vectores anteriores... para cada casilla adyacente...
	for(int k=0;k<8;k++){
		if(auxx[k]>=0 && auxx[k]<7 && auxy[k]>=0 && auxy[k]<7){  // Sirve para evitar comprobar casillas que se salgan fuera del tablero
				i=auxy[k];
				j=auxx[k];
				if(tab[i][j]!=0 && tab[i][j]!=turno){ // compruebo si no está vacía y no es mia...entonces es del contrincante
					tab[i][j]=turno;  // La convierto en mía
					// Actualizo el contador de fichas
					if(turno==1){
						fichas[0]++;
						fichas[1]--;

					}
					if(turno==2){
						fichas[0]--;
						fichas[1]++;
					}
				}
		}
	}

	repaint();

}

int Tablero::cuantasCome(int fila, int columna){
	int i,j;
	int comidas=0;
	// Vectores auxiliares que emparejados identifican las casillas que rodean a una casilla dada
	int auxy[8]={fila-1,   fila-1, fila-1,   fila,     fila,     fila+1,   fila+1, fila+1};	
	int auxx[8]={columna-1,columna,columna+1,columna-1,columna+1,columna-1,columna,columna+1};
	// Recorro los vectores anteriores... para cada casilla adyacente...
	for(int k=0;k<8;k++){
		if(auxx[k]>=0 && auxx[k]<7 && auxy[k]>=0 && auxy[k]<7){  // Sirve para evitar comprobar casillas que se salgan fuera del tablero
				i=auxy[k];
				j=auxx[k];
				if(tab[i][j]!=0 && tab[i][j]!=turno){ // compruebo si no está vacía y no es mia...entonces es del contrincante
					comidas++;  // La convierto en mía
				}
		}
	}
	return comidas++;
}

void Tablero::mover(){

	// Creo un widget QTimer que a los 1500 milisegundos genera la señal que llama a generarMovimiento. Asi simulamos que el computador "esta pensando".
	QTimer *timer = new QTimer(this);
	connect(timer, SIGNAL(timeout()), this, SLOT(generaMovimiento()));
	timer->setSingleShot(true);
     	timer->start(1500);
}

void Tablero::generaMovimiento(){
	if(puedeMover(2)){
		int incx[] = { -1, -1, -1, 0, 0, 1, 1, 1};
		int incy[] = { -1, 0, 1, -1, 1, -1, 0, 1};
		int incx2[] = { -2, -2, -2, -2, -2, -1, -1, 0, 0, 1, 1, 2, 2, 2, 2, 2};
		int incy2[] = { -2, -1, 0, 1, 2, -2, 2, -2, 2, -2, 2, -2, -1, 0, 1, 2};
	
		casilla max1, max2, orig1, orig2;
		int beneficio1=-1,beneficio2=-1; // Coordenadas de la casilla que me produce mayor beneficio en uno de sus movimientos

		// Recorro el tablero buscando fichas mias
		for(int y=0;y<7;y++){
			for(int x=0;x<7;x++){
				if(tab[y][x]==turno){ // Si es mia
					fila_origen=y;
					col_origen=x;

					// Compruebo cuantas me comeria si muevo en todas las posibilidades de distancia 1 dada la casilla actual
					for(int k=0;k<8;k++){
						casilla aux1;
						aux1.columna=x+incx[k];
						aux1.fila=y+incy[k];
						if(aux1.columna>=0 && aux1.fila>=0 && aux1.columna<7 && aux1.fila<7 && tab[aux1.fila][aux1.columna]==0){
							// Incremento en 1 porque cuando la distancia es 1 ademas de las que me como, se agrega una ficha mas.
							int auxbeneficio=cuantasCome(aux1.fila,aux1.columna)+1;  
							if(auxbeneficio>=beneficio1){
								beneficio1=auxbeneficio; // Este seria el nuevo beneficio a superar
								// Guardo la casilla destino que me produce mayor beneficio hasta el momento
								max1.fila=aux1.fila;
								max1.columna=aux1.columna;

								// Guardo la casilla origen de la que parto para obtener el mayor beneficio
								orig1.fila=y;
								orig1.columna=x;

							}
						}
					}


					// Compruebo cuantas me comeria si muevo en todas las posibilidades a distancia 2
					for(int k=0;k<16;k++){
						casilla aux2;
						aux2.columna=x+incx2[k];
						aux2.fila=y+incy2[k];
						if(aux2.columna>=0 && aux2.fila>=0 && aux2.columna<7 && aux2.fila<7 && tab[aux2.fila][aux2.columna]==0){
							int auxbeneficio=cuantasCome(aux2.fila,aux2.columna);
							if(auxbeneficio>=beneficio2){
								beneficio2=auxbeneficio;// Este seria el nuevo beneficio a superar
								// Guardo la casilla destino que me produce mayor beneficio hasta el momento
								max2.fila=aux2.fila;
								max2.columna=aux2.columna;

								// Guardo la casilla origen de la que parto para obtener el mayor beneficio
								orig2.fila=y;
								orig2.columna=x;
							}
						}
					}



				}
			}
		}
		
		if(beneficio1>=beneficio2){
			tab[max1.fila][max1.columna]=turno;  // Pongo una nueva ficha
			fichas[1]++;
			compruebaMovimiento(max1.fila,max1.columna);
		}else{
			tab[max2.fila][max2.columna]=turno;  // Pongo una nueva ficha
			tab[orig2.fila][orig2.columna]=0;
			compruebaMovimiento(max2.fila,max2.columna);
			
		}
		repaint();
	}
	cambiaturno();
	guardaMovimiento();
	compruebaGanar();
}

void Tablero::compruebaGanar(){
	// Comprobaciones que determinan si se ha terminado la partida
	QString mensaje;
	if(fichas[0]==0){ // Si el jugador 1 no tiene fichas...
		mensaje=coloresfichas[ficha2];  // gana el jugador 2
		emit ganador(mensaje);
	}else if(fichas[1]==0){  // Si el jugador 2 no tiene fichas...
		mensaje=coloresfichas[ficha1]; // gana el jugador 1
		emit ganador(mensaje);
	}else if(!puedeMover(1) && !puedeMover(2)){  // Si ninguno de los dos puede mover...
		if(fichas[0]>fichas[1]){ // ...y tiene mas fichas el jugador 1 en el tablero...
			mensaje=coloresfichas[ficha1];  // gana el jugador 1
			emit ganador(mensaje);
		}else if(fichas[0]<fichas[1]){  // ... en el caso de que el jugador 2 tenga mas fichas en el tablero...
			mensaje=coloresfichas[ficha2];  // gana el jugador 2
			emit ganador(mensaje);
		}
	}
}

void Tablero::paintEvent(QPaintEvent *event){


	if(event!=0){ // Evita aviso de event sin uso xD
	}


	QPainter painter(this);

	// Cargo las imagenes que se van a usar en el juego

	int casilla=this->height()/7;

	// Pinto el tablero
	painter.drawImage(0, 0, fondo);
	
	// Recorro las filas del tablero
	for(int i=0;i<7;i++){
		// Para cada fila, recorro las columnas
		for(int j=0;j<7;j++){
			// Si la casilla no está vacía...
			if(tab[i][j]!=CASILLA_VACIA){
				int y=(i*casilla);
				int x=(j*casilla);
				if(tab[i][j]==CASILLA_J1)  // Si es del jugador 1...
					painter.drawImage(x, y, imagenficha1);  //  Pongo una ficha roja
				else if(tab[i][j]==CASILLA_J2)  // Si es del jugador 2 ...
					painter.drawImage(x, y, imagenficha2);  // Pongo una ficha azul
				
			}
		}
	}

	if(casilla_sel){
		// Pintamos la casilla resaltada
		painter.setPen(QPen(Qt::yellow, 1, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));  // Establezco color a amarillo
		painter.drawLine(col_origen*80,fila_origen*80,col_origen*80+80,fila_origen*80);  // Linea horizontal superior
		painter.drawLine(col_origen*80,fila_origen*80+80,col_origen*80+80,fila_origen*80+80);  // Linea horizontal inferior
		painter.drawLine(col_origen*80,fila_origen*80,col_origen*80,fila_origen*80+80);  // Línea vertical izquierda
		painter.drawLine(col_origen*80+80,fila_origen*80,col_origen*80+80,fila_origen*80+80);  // Línea vertical derecha

	}


	
	painter.end();	
}

casilla Tablero::getCasilla(int x, int y){
	casilla aux;
	aux.fila = y/80;
	aux.columna= x/80;
	return aux;
}

void Tablero::guardaMovimiento(){
	// Si se han deshecho movimento y no se han rehecho todos, es decir, estamos en movimientos anteriores y ejecutamos un movimiento...
	// se vacia toda la cola a partir del index_movimientos para que no se pueda avanzar a movimientos que ya no tienen sentido porque
	// se ha seguido otro curso del juego.
	if(retrocesos<0)
		for(int i=index_movimientos+1;i<=movimientos.size();i++){
			movimientos.removeAt(i);
		}



	index_movimientos++;
	estado aux;
	for(int i=0;i<7;i++){
		for(int j=0;j<7;j++){
			aux.tab[i*7+j]=tab[i][j];
		}
	}
	aux.tab[49]=turno;
	movimientos.insert(index_movimientos,aux);
}

void Tablero::anterior(){
	if(index_movimientos-1<movimientos.size() && index_movimientos-1>=0){
		retrocesos--;
		if(tipo_oponente==0){
			estado aux=movimientos.at(index_movimientos-1);
			for(int i=0;i<7;i++){
				for(int j=0;j<7;j++){
					tab[i][j]=aux.tab[i*7+j];
				}
			}
			turno=aux.tab[49];
			index_movimientos--;
			
			repaint();
		}else if(tipo_oponente==1){
			bool encontrado=false;
			int j=index_movimientos-1;
			estado aux;
			while(!encontrado && j>=0){
				aux=movimientos.at(j);
				if(aux.tab[49]==1){
					encontrado=true;
					for(int i=0;i<7;i++){
						for(int j=0;j<7;j++){
							tab[i][j]=aux.tab[i*7+j];
						}
					}
					turno=aux.tab[49];
					index_movimientos=j;
					repaint();
				}
				j--;
			}
		}
	}
}

void Tablero::siguiente(){
	if(index_movimientos+1<movimientos.size() && index_movimientos+1>=0){
		retrocesos++;
		if(tipo_oponente==0){	
			estado aux=movimientos.at(index_movimientos+1);
			for(int i=0;i<7;i++){
				for(int j=0;j<7;j++){
					tab[i][j]=aux.tab[i*7+j];
				}
			}
			turno=aux.tab[49];
			index_movimientos++;
			repaint();
		
		}else if(tipo_oponente==1){
			bool encontrado=false;
			int j=index_movimientos+1;
			estado aux;
			while(!encontrado && j>=0){
				aux=movimientos.at(j);
				if(aux.tab[49]==1){
					encontrado=true;
					for(int i=0;i<7;i++){
						for(int j=0;j<7;j++){
							tab[i][j]=aux.tab[i*7+j];
						}
					}
					turno=aux.tab[49];
					index_movimientos=j;
					repaint();
				}
				j++;
			}
		}
	}
}

void Tablero::nuevo(){
	// Libero todas las casillas
	for(int i=0;i<7;i++){
		for(int j=0;j<7;j++){
			tab[i][j]=CASILLA_VACIA;
		}
	}
	// Inicializo las 4 fichas de las esquinas
	tab[0][0]=2;
	tab[6][0]=1;
	tab[0][6]=1;
	tab[6][6]=2;

	// Actualizo el contador de fichas
	fichas[0]=2; // 2 fichas para el jugador
	fichas[1]=2; // 2 fichas para el oponente

	// Establezco el turno
	turno=CASILLA_J1;
	casilla_sel=false;

	// Vacío la lista de movimientos realizados.
	index_movimientos=-1;
	movimientos.clear();
	retrocesos=0;

	// Guardo el estado inicial del tablero
	guardaMovimiento();

	QString mensaje("Turno del jugador ");
	mensaje+=coloresfichas[ficha1];
	emit turnocambiado(mensaje);
	this->repaint();
}

bool Tablero::guardar(const QString &fileName){
	QFile file(fileName);
	if(file.open(QIODevice::WriteOnly)){
	QDataStream out(&file);
		for(int i=0;i<7;i++){
			for(int j=0;j<7;j++){
				out << (int) tab[i][j];
			}
		}
		out << turno;
		out << tipo_oponente;
		out << ficha1;
		out << ficha2;
		out << fichas[0];
		out << fichas[1];
		return true;
	}else{
		return false;
	}
}

bool Tablero::abrir(const QString &fileName){
	QFile file(fileName);
	if(file.open(QIODevice::ReadOnly)){
		QDataStream in(&file);

		for(int i=0;i<7;i++){
			for(int j=0;j<7;j++){	
				in >> tab[i][j];
			};
		}
		in >> turno;
		in >> tipo_oponente;
		in >> ficha1;
		in >> ficha2;
		setColorFicha(1,ficha1);
		setColorFicha(2,ficha2);
		in >> fichas[0];
		in >> fichas[1];
		this->repaint();
		return true;
	}else{
		return false;
	}
}

void Tablero::cambiaturno(){
	QString mensaje;
	mensaje="Turno del jugador ";
	if(turno==CASILLA_J1 && puedeMover(2)){
		turno=CASILLA_J2;
		
		if(tipo_oponente==1){
			mensaje+=coloresfichas[ficha2];
			mensaje+=" (ordenador)... Esta pensando...";
			emit turnocambiado(mensaje);
			mover();
		}else{
			mensaje+=coloresfichas[ficha2];
			emit turnocambiado(mensaje);
		}
	}else if(turno==CASILLA_J2 && puedeMover(1)){
		turno=CASILLA_J1;
		mensaje+=coloresfichas[ficha1];
		emit turnocambiado(mensaje);
	}
	
}
